\section{Desarrollo}
\noindent El desarrollo de este trabajo puede analizarse en tres partes: el manejo de imágenes, el muestreo y los algoritmos.
\\
\\
Para el manejo de imágenes, es decir cargarlas, colocarles ruido y luego convertirlas a la matriz $A$ con la que trabajaremos, utilizamos varias funciones. Primero
\textit{crearAyB}, esta función se encarga de levantar el archivo de imagen y recorrer los píxeles creando la matriz que representara el sistema de ecuaciones.
Esta función comienza levantando la información de la imagen que viene almacenada en los primeros bytes de la imagen (ancho, altura, valor máximo en escala de grises, etc).
De esta información nos guardamos solamente el tamaño de la imagen, es decir el ancho y la altura (el resto de la información no nos será de utilidad).
\\
Luego, una vez recuperado el ancho y alto de la imagen procedemos a recorrerla, creando el vector $b$ (recordemos que lo que tratamos de resolver es $Ax = b$) que será
la representación de la imagen original mas el/los pixeles adecuados del borde creado, pero en vez de verla como matriz se ve como un vector de tamaño $n*m$, donde cada posición equivaldrá a un píxel de la imagen original.
Cada posición estará multiplicada por $\lambda$ (como muestra la ecuación $3$ en el \textit{Enunciado}).
\\
La siguiente función a utilizar es \textit{CargarMatriz}, la cual se encargará de crear la matriz $A$. Lo que hace es crear una matriz de tamaño $(n*m)*(n*m)$
y la recorre llenándola con los valores $-1$, $0$ o $(\lambda + 4)$ según corresponda. Es decir para la fila $(i*n+j)$ que corresponde al píxel $(i,j)$ llenará la columna
$(i*n+j)$ (columna que corresponde al píxel $(i,j)$) con el valor $(\lambda + 4)$, las columnas $((i+1)*n+j)$, $((i-1)*n+j)$, $(i*n+j+1)$, $(i*n+j-1)$ (corresponden a los píxeles 
$(i+1,j)$, $(i-1,j)$, $(i,j+1)$, $(i,j-1)$ respectivamente) con el valor $-1$, y el resto de las columnas con el valor $0$. Realiza este procedimiento para todas las filas (todos los
píxeles), pero se fija si esta recorriendo los bordes, dado que las filas que son parte del borde (las filas que representan a los píxeles del borde de la imagen)
reducen la cantidad de valores $-1$ que contienen, por ejemplo para los píxeles de la primer fila (de la imagen) no existe el píxel $(i-1,j)$, es por ello que estos valores
se setean en $0$.
\\\\
.~~~~~b ~~~~l~~~~~ k\\
$\begin{matrix}a \\ c \\d \end{matrix} $
$\begin{bmatrix} 

\widehat x_1 & \widehat x_2 & \widehat x_3\\ 
\widehat x_4 & \widehat x_5 & \widehat x_6\\ 
\widehat x_7 & \widehat x_8 & \widehat x_9

\end{bmatrix} \begin{matrix}j \\ i \\h \end{matrix}  \Longrightarrow \begin{bmatrix} 

x_1 &  x_2 & x_3\\ 
x_4 & x_5 & x_6\\ 
x_7 & x_8 & x_9

\end{bmatrix} ~~~~~~~ \lambda\widehat x_1 = x_1(\lambda+4)-x_2-x_4-a-b ~~~~~~~~c=(\widehat x_1 + \widehat x_4 +\widehat x_7)/3$
\\\noindent .~~~~~~e~~~~~f~~~~~g$~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\lambda\widehat x_2 = x_2(\lambda+4)-x_1-x_3-x_5-l ~~~~a=(\widehat x_1+\widehat x_4)/2 ~~~\\~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ b=(\widehat x_1+\widehat x_2)/2$\\\\
$ A = \begin{bmatrix} 

 (\lambda+4)&-1&0&-1&0&0&0&0&0\\ \\
 -1&(\lambda+4)&-1&0&-1&0&0&0&0\\ \\
 0&-1&(\lambda+4)&0&0&0&-1&0&0\\ \\
 -1 & 0 & -1&(\lambda+4) & -1 & 0 & -1 & 0 & 0\\ \\
 0&-1&0&-1&(\lambda+4)&-1&0&-1&0\\ \\
 0&0&-1&0&-1&(\lambda+4)&0&0&-1\\ \\
 0&0&0&-1&0&0&(\lambda+4)&-1&0\\ \\
 0&0&0&0&-1&0&-1&(\lambda+4)&-1\\ \\
 0&0&0&0&0&-1&0&-1&(\lambda+4)

\end{bmatrix} \\$

$x = \begin{bmatrix} x_1 \\ x_2 \\ x_3 \\ x_4 \\ x_5 \\ x_6 \\ x_7 \\ x_8 \\ x_9 \\ \end{bmatrix} ~~~~~~~~~~b = \begin{bmatrix} 

\lambda \widehat x_1+a+b \\ \lambda \widehat x_2+l \\ \lambda \widehat x_3+k+j\\ 
\lambda \widehat x_4+c \\ \lambda \widehat x_5 \\ \lambda \widehat x_6+i\\ 
\lambda \widehat x_7+d+e \\ \lambda \widehat x_8+f \\ \lambda \widehat x_9+g+h

\end{bmatrix}$
\\
\\
Para colocarles ruido a las imágenes utilizamos el programa Gimp. Este programa nos permitió agregarles distintos tipos de ruido a las imágenes variando 
ciertos parámetros. Los tipos de ruido que utilizamos son: Hurl, que lo que hace es cambiar el valor de cada píxel a distinto color, lo que hicimos fue variar
el parámetro de \textit{Randomization(\%)} (esto varía el porcentaje de los píxeles afectados) y el \textit{Repeat} (que es la cantidad de veces que se
repite el filtro para generar ruido). 
\\
Otro tipo de ruido utilizado fue el ruido Pick, este ruido reemplaza cada píxel por un valor aleatorio, pero a diferencia
de Hurl, este valor es de alguno de sus vecinos. Para este ruido variamos los mismos parámetros \textit{Randomization(\%)} y \textit{Repeat}.
\\
Otro tipo fue el RGB que genera el ruido distribuído normalmente a una parte de la imagen, usa el modo de color RGB para producir el ruido, es decir agrega ruido a los
valores rojo, verde y azul de cada píxel, sin embargo como trabajamos con escala de grises solo afecta al valor \textit{Grey} que es el parámetro que variamos.
\\
El último tipo de ruido utilizado fue el Spread, este se genera variando el valor de un píxel de la imagen por el valor de otro píxel de la imagen seleccionado
al azar. Los parámetros que variamos en este caso fue \textit{Spread Amount} que consiste en seleccionar la sección de donde tomaré los píxeles de manera aleatoria,
esto se hace variando los valores de \textit{Horizontal} y \textit{Vertical} que definen hasta que distancia del píxel a modificar tomaré píxeles aleatorios.
\\
\\
Se pide que el programa implementado sea capaz de procesar imágenes de gran tamaño. Para ello se crearon dos métodos subMuestreo() y sobreMuestreo(). El método de subMuestreo recibe dos parametros la imagen que se quiere reducir (llamemosla imagen original) y el factor de reduccion. El objetivo es crear una imagen reducida (llamemosla imagen nueva) dependiendo del factor de reduccion, este factor va tomar valores entre 1 y 100 que serian el porcentaje de reduccion. La idea del algoritmo que implementa el método de submuestreo es el siguiente: Ir tomando cada uno de los pixels de la imagen original. Los pixels tomados ubicarlos en la imagen nueva. La manera en que se decide la posición en la imagen nueva depende del factor de reduccion. Si ya hay un pixel en la posición de la imagen nueva sumarlo. Una vez que se recorrio toda la imagen original, dividir cada posición de la imagen nueva por la cantidad de pixels que se acumularon en esa posición.
\begin{verbatim}
reducir = (100 - fr)/100

Para x entre 0 y el alto de la imagenOriginal
    Para y entre 0 y el ancho de la imagenOriginal
        xx = x * reducir
        yy = y * reducir
        imagenNueva[xx, yy] = imagenNueva[xx, yy] + imagenOriginal[x, y]
        contador[xx, yy] = contador[xx, yy] + 1
    Fin Para
Fin Para
\end{verbatim}
Es decir, siendo fr el factor de reduccion, se tiene que reducir = (100 - fr)/100. La variable reducir calcula un valor que multiplicando las posiciones obtendra la posición proporcional correcta en donde ubicar el pixel. El contador va guardando la cantidad de pixels que se acumularon en cada posición de la imagen nueva. Luego finalmente se divide cada posición.
\begin{verbatim}
Para xx entre 0 y el alto de la imagenNueva
    Para yy entre 0 y el ancho de la imagenNueva
        imagenNueva[xx, yy] = imagenNueva[xx, yy]/contador[xx, yy]
    Fin Para
Fin Para
\end{verbatim}
De esta manera se reduce la imagen. El sobremuestreo realiza tiene la misma idea pero a la inversa. Cada pixel de la imagen original va a terminar en un posición de una imagen nueva dependiendo de el factor de reduccion que se le pase.
\begin{verbatim}
reducir = (100 - fr)/100
aumentar = 100/(100 - fr)
nuevoAncho = anchoImagenOriginal * aumentar
nuevoAlto = altoImagenOriginal * aumentar

Para x entre 0 y nuevoAlto
    Para y entre 0 y nuevoAncho
        xx = x * reducir
        yy = y * reducir
        imagenNueva[x, y] = imagenOriginal[xx, yy]
    Fin Para
Fin Para
\end{verbatim}
En la parte de algoritmos podemos encontrar el algoritmo de Gauss y el algoritmo para resolver una matriz triangular superior (para una inferior es análogo el procedimiento).
El algoritmo de Gauss recibe una matriz $m$ y un vector $b$ y nos devuelve el vector solución $x$. Lo que primero que hace es agregar una columna mas a la matriz $m$, donde
esta nueva columna será el vector $b$. Luego comienza a hacer las $n$ iteraciones:
\begin{verbatim}
for(int k = 1; k<= n; k++)      // k = iteraciones
{
  if(k < n - sqrt(n)){
    for(int i = k+1; i <= k + floor(sqrt(n)) + 1; i++)     // i = fila
    {
      float mik = m.get(i,k);
      for(int j = k; j <= k + floor(sqrt(n)) + 1; j++)     // j = columna
      {
	float valor = m.get(i,j)-m.get(k,j)*mik/m.get(k,k);
	m.set(i,j,valor);    // voy modificando la matriz dejando en 0 la triangular inferior
      }
    }
  }else{
    for(int i = k+1; i <= n; i++)     // i = fila
    {
      float mik = m.get(i,k);
      for(int j = k; j <= n; j++)     // j = columna
      {
	float valor = m.get(i,j)-m.get(k,j)*mik/m.get(k,k);
	m.set(i,j,valor);    // voy modificando la matriz dejando en 0 la triangular inferior
      }
    }
  }
}
\end{verbatim}
Como podemos ver por cada iteración recorremos la parte de la matriz que aun no esta triangulada y realizamos los cálculos para dejar la columna que corresponde a la iteración actual
en 0, modificando las demás. Sin embargo no realizamos las cuentas para todas las sumas, en este algoritmo de Gauss aprovechamos la distribución de los valores de la matriz, recordemos
que por como estaba construida, muchos valores eran 0. Es por esto que al momento de recorrer las filas, recorremos solo hasta que aparece el valor $-1$ dado que 
después son todos 0. Por como esta formada la matriz sabemos que el valor $-1$ corresponde al píxel $(i+1,j)$ que se encuentra en la columna $k + \sqrt{n}$ dado que como 
el tamaño de la matriz es el cuadrado del tamaño de la matriz original (de las dimensiones de la imagen cuadrada) entonces el ancho de la imagen debe ser la raíz de la matriz $A$.
Luego $k+\sqrt{n} = k + anchoImagen$, y con esta suma alcanzamos la posición del píxel que vale $-1$ en la matriz $A$ (es el que esta debajo del píxel $(i,j)$ en la imagen
original). Otro dato a tener en cuenta es que para los píxeles que están en la última fila de la imagen no existen píxeles debajo de ellos, es por eso que en caso de que
$k < n - \sqrt{n}$ no recuperamos el valor de la matriz que corresponde a los píxeles de la fila ``de abajo'' (nos tiraría la excepción \textit{Violación de segmento}).
Una vez terminado el algoritmo tenemos en $m$ una matriz triangular. Ahora realizamos el algoritmo para resolver matrices triangulares: 
\begin{verbatim}
for(int k = n-1; k > 0; k--)      // calculamos el vector x con el metodo de matriz triangular
{
  valorX = (b[k-1] - suma(k, m, x))/m.get(k,k);
  x[k-1]= valorX;
}
\end{verbatim}
Como podemos ver lo que hace es recorrer desde la última fila hasta la primera, todas las filas, despejando el $valorX$ que es el valor del vector $x$ en la posición que 
corresponde a esa fila. La función $suma$ simplemente implementa la sumatoria: $\sum_{j=i}^{\sqrt{n}}{x_j * m_{ij}}$ (Realizamos la suma hasta $\sqrt{n}$ por la
misma razón que en Gauss, el resto de los valores son 0).
\\
Luego retorna el vector solución $x$ que es lo que también retornará $Gauss$.
